package downpacket

import (
	"encoding/json"

	"gitee.com/yanwc/ebike-xiaoan-device/internal/codec"
	"gitee.com/yanwc/ebike-xiaoan-device/internal/field"
)

type downPacket struct {
	CmdWord CommandWord `json:"c"`
	Param   interface{} `json:"param"`
}

type ErrorCode int

const (
	CODE_SUCCESS                        = ErrorCode(0)
	CODE_RANGE_TOO_LARGE                = ErrorCode(105)
	CODE_MEM_NOT_ENOUGH                 = ErrorCode(110)
	CODE_CMD_NOT_SUPPORT                = ErrorCode(111)
	CODE_PARAM_INVALID                  = ErrorCode(114)
	CODE_PARAM_MISSING                  = ErrorCode(115)
	CODE_ERR_HTTP_CID                   = ErrorCode(116)
	CODE_ERR_HTTP_URL                   = ErrorCode(117)
	CODE_ERR_HTTP_USER_DATA             = ErrorCode(118)
	CODE_ERR_HTTP_WRITE_DATA            = ErrorCode(119)
	CODE_ERR_HTTP_ACTION                = ErrorCode(120)
	CODE_ERR_HTTP_POST_READ             = ErrorCode(121)
	CODE_ERR_HTTP_IS_PROCING            = ErrorCode(122)
	CODE_ERR_HTTP_READ_FILE             = ErrorCode(123)
	CODE_ERR_HTTP_MOVED_PERMANENTLY     = ErrorCode(124) // 301 error
	CODE_ERR_HTTP_NOTFOUND              = ErrorCode(125) // 404 error
	CODE_ERR_HTTP_REQUEST_TIMEOUT       = ErrorCode(126) // 408 error
	CODE_ERR_HTTP_INTERNAL_SERVER_ERROR = ErrorCode(127) // 500 error
	CODE_ERR_HTTP_GATEWAY_TIMEOUT       = ErrorCode(128) // 504 error
	CODE_ERR_HTTP_NETWORK_ERROR         = ErrorCode(129) // 601 error
	CODE_ERR_HTTP_DNS_ERROR             = ErrorCode(130) // 603 error
	CODE_ERR_FILE_ERROR                 = ErrorCode(131) // 设备存储失败
	CODE_ERR_CAR_NOT_STOP               = ErrorCode(132) // 车辆未停止
	CODE_ERR_UPGRADE_CRC_ERROR          = ErrorCode(133) // crc校验失败
	CODE_ERR_OPEN_GPRS_FAILED           = ErrorCode(134) // http操作失败
	CODE_ERR_OPERATION_TIMEOUT          = ErrorCode(135) // 设备操作超时
	CODE_ERR_OPERATION_ERROR            = ErrorCode(136)
	CODE_ERR_OUT_OF_TIME                = ErrorCode(137)
	CODE_ERR_CONTINUALLY                = ErrorCode(138)
	CODE_ERR_ACCESS_DENY                = ErrorCode(139)
	CODE_ERR_OTA_UPGRADING              = ErrorCode(140)
)

func (ec ErrorCode) Description() string {
	if v, ok := errorCodes[ec]; ok {
		return v
	} else {
		return ""
	}
}

var errorCodes = map[ErrorCode]string{
	CODE_SUCCESS:                        "操作成功",
	CODE_RANGE_TOO_LARGE:                "请求范围过大",
	CODE_MEM_NOT_ENOUGH:                 "设备内存错误",
	CODE_CMD_NOT_SUPPORT:                "设备不支持该指令",
	CODE_PARAM_INVALID:                  "参数不合法",
	CODE_PARAM_MISSING:                  "参数缺失",
	CODE_ERR_HTTP_CID:                   "HTTPCID错误",
	CODE_ERR_HTTP_URL:                   "HTTPURL错误",
	CODE_ERR_HTTP_USER_DATA:             "HTTPUSERDATA错误",
	CODE_ERR_HTTP_WRITE_DATA:            "post数据写入modem时错误",
	CODE_ERR_HTTP_ACTION:                "HTTPACTION除去常301 500 601 603 404错误的其他错",
	CODE_ERR_HTTP_POST_READ:             "post读取服务器返回数据失败",
	CODE_ERR_HTTP_IS_PROCING:            "http中正在执行进程",
	CODE_ERR_HTTP_READ_FILE:             "post中读取文件数据失败",
	CODE_ERR_HTTP_MOVED_PERMANENTLY:     "301 error",
	CODE_ERR_HTTP_NOTFOUND:              "404 error",
	CODE_ERR_HTTP_REQUEST_TIMEOUT:       "408 error",
	CODE_ERR_HTTP_INTERNAL_SERVER_ERROR: "500 error",
	CODE_ERR_HTTP_GATEWAY_TIMEOUT:       "504 error",
	CODE_ERR_HTTP_NETWORK_ERROR:         "601 error",
	CODE_ERR_HTTP_DNS_ERROR:             "603 error",
	CODE_ERR_FILE_ERROR:                 "设备存储失败",
	CODE_ERR_CAR_NOT_STOP:               "车辆未停止",
	CODE_ERR_UPGRADE_CRC_ERROR:          "crc校验失败",
	CODE_ERR_OPEN_GPRS_FAILED:           "http操作失败",
	CODE_ERR_OPERATION_TIMEOUT:          "设备操作超时",
	CODE_ERR_OPERATION_ERROR:            "设备操作失败",
	CODE_ERR_OUT_OF_TIME:                "命令超时",
	CODE_ERR_CONTINUALLY:                "操作过于频繁",
	CODE_ERR_ACCESS_DENY:                "超级锁车功能开启，无法操作",
	CODE_ERR_OTA_UPGRADING:              "控制器或者BMS OTA升级中，无法操作",
}

func WrapDownPacket[T any](req Req[T]) (out []byte, err error) {
	dp := &downPacket{
		CmdWord: req.CmdWord,
		Param:   req.Param,
	}

	d, err := json.Marshal(&dp)
	if err != nil {
		return
	}

	frame := codec.NewFrame(field.WildCommandWord, field.SerialNumber(req.MsgNo))
	out = frame.WrapPacket(d)
	return
}

type Resp[T any] struct {
	Code   ErrorCode `json:"code"`
	Result T         `json:"result"`
}

type Req[T any] struct {
	CmdWord CommandWord
	Param   T
	MsgNo   field.SerialNumber
}
